package cn.anecansaitin.whimsy.common.effect.ow.doomfist;

import cn.anecansaitin.whimsy.Whimsy;
import cn.anecansaitin.whimsy.client.registers.ModSounds;
import cn.anecansaitin.whimsy.common.attachment.DoomfistSkill;
import cn.anecansaitin.whimsy.common.attachment.ImpactData;
import cn.anecansaitin.whimsy.common.attachment.SpeedData;
import cn.anecansaitin.whimsy.common.network.ClientRocketPunchStopPack;
import cn.anecansaitin.whimsy.common.network.NetworkHelper;
import cn.anecansaitin.whimsy.common.network.RocketPunchHitPack;
import cn.anecansaitin.whimsy.common.network.ServerRocketPunchStopPack;
import cn.anecansaitin.whimsy.common.register.ModDamageSources;
import cn.anecansaitin.whimsy.common.register.ModDataAttachments;
import cn.anecansaitin.whimsy.common.register.ModEffects;
import cn.anecansaitin.whimsy.common.register.ModItems;
import cn.anecansaitin.whimsy.util.AABBUtil;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;

import java.util.List;

@Mod.EventBusSubscriber(modid = Whimsy.MODID)
public class RocketPunch extends MobEffect {
    public RocketPunch() {
        super(MobEffectCategory.BENEFICIAL, 0);
    }

    @Override
    public void onEffectStarted(LivingEntity livingEntity, int amplifier) {
        if (!livingEntity.level().isClientSide) {
            livingEntity.level().playSound(null, livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(), ModSounds.ROCKET_PUNCH_START.get(), SoundSource.PLAYERS);
        }
    }

    @Override
    public void applyEffectTick(LivingEntity livingEntity, int amplifier) {
        if (!(livingEntity instanceof LocalPlayer)) {
            return;
        }

        Vec3 vec3 = livingEntity.getViewVector(1).multiply(1, 0, 1).normalize();
        double velocity;

        if (amplifier == 0) {
            velocity = 1.2;
        } else {
            velocity = 1.8;
        }

        //为了让玩家在冲刺中停下来，比如撞到墙壁，检测速度是否小于一定值
        {
            SpeedData data = livingEntity.getData(ModDataAttachments.SPEED_DATA);

            if (!data.isNull) {
                double xOld = data.x;
                double zOld = data.z;
                double x = livingEntity.getX();
                double z = livingEntity.getZ();
                double distance = Math.pow(x - xOld, 2) + Math.pow(z - zOld, 2);

                if (distance < 0.5) {
                    NetworkHelper.toServerPlayer(new ServerRocketPunchStopPack());
                }
            }

            data.isNull = false;
            data.x = livingEntity.getX();
            data.y = livingEntity.getY();
            data.z = livingEntity.getZ();
        }

        for (Entity entity : livingEntity.level().getEntities(livingEntity, livingEntity.getBoundingBox().expandTowards(livingEntity.getDeltaMovement()).inflate(1.0), entity -> entity instanceof LivingEntity)) {
            if (AABBUtil.isMovingEntityCollisionWithEntity(livingEntity, entity, 0.8)) {
                NetworkHelper.toServerPlayer(new RocketPunchHitPack(entity.getId()));
                return;
            }
        }

        livingEntity.setDeltaMovement(vec3.scale(velocity));
    }

    @Override
    public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
        return true;
    }

    @SubscribeEvent
    public static void onEffectRemove(MobEffectEvent.Remove event) {
        if (event.getEffect() == ModEffects.ROCKET_PUNCH.get() && event.getEntity() instanceof ServerPlayer player) {
            onEffectFinished(player);
        }
    }

    @SubscribeEvent
    public static void onEffectExpired(MobEffectEvent.Expired event) {
        if (event.getEffectInstance().getEffect() == ModEffects.ROCKET_PUNCH.get() && event.getEntity() instanceof ServerPlayer player) {
            onEffectFinished(player);
        }
    }

    private static void onEffectFinished(ServerPlayer player) {
        player.setDeltaMovement(Vec3.ZERO);
        player.getMainHandItem().getData(ModDataAttachments.DOOMFIST_SKILL).rocketPunch.castingComplete();
        NetworkHelper.toClientPlayer(player, new ClientRocketPunchStopPack());
    }

    public static void hurtEntity(LivingEntity attacker, LivingEntity entity) {
        ItemStack item = attacker.getMainHandItem();

        if (!item.is(ModItems.DOOMFIST.get())) {
            return;
        }

        attacker.level().playSound(null, attacker.getX(), attacker.getY(), attacker.getZ(), ModSounds.ROCKET_PUNCH_HIT.get(), SoundSource.PLAYERS);
        DoomfistSkill skill = item.getData(ModDataAttachments.DOOMFIST_SKILL);
        float chargedRate = skill.rocketPunch.rechargeTick / 20f;
        float enhanced = skill.rocketPunch.isEnhanced ? 1.5f : 1;
        Vec3 v = attacker.getViewVector(1).multiply(1, 0, 1).normalize().scale(2.5 * enhanced);

        //击中敌人后有范围效果
        List<LivingEntity> enemies = entity.level().getEntitiesOfClass(LivingEntity.class, entity.getBoundingBox().inflate(1.5));
        //剔除自己
        enemies.remove(attacker);
        //添加临时护盾
        attacker.setAbsorptionAmount(attacker.getAbsorptionAmount() + enemies.size() * 3.5f);
        skill.ultimateEfficiency.generate();

        for (LivingEntity livingEntity : enemies) {
            livingEntity.invulnerableTime = 9;
            livingEntity.hurt(ModDamageSources.owNoKnockback(livingEntity.level(), attacker, null, attacker.position()), 7.5f * chargedRate * enhanced);//伤害
            //由于effect本身无法保存额外的数据，所以使用这种方法保存被击退的方向
            ImpactData data = livingEntity.getData(ModDataAttachments.IMPACT_MOVEMENT_DATA);
            data.x = v.x;
            data.y = v.y;
            data.z = v.z;
            data.chargedRate = chargedRate;
            data.isEnhanced = enhanced > 1;
            livingEntity.setData(ModDataAttachments.IMPACT_MOVEMENT_DATA, data);
            int i = (int) (chargedRate * 5.2);//持续时间
            livingEntity.addEffect(new MobEffectInstance(ModEffects.IMPACT.get(), i));
            livingEntity.addEffect(new MobEffectInstance(ModEffects.STUN.get(), i));
        }

        attacker.removeEffect(ModEffects.ROCKET_PUNCH.get());
    }
}
